package packet

import (
	"encoding/binary"
	"github.com/spf13/cast"
	"time"
)

const (
	// HeaderLength is the total length of the packet header in bytes
	HeaderLength = 28

	// Source/Destination identifiers
	IDTianlianCenter = 0x21580001

	// Data flags
	FlagLinkMonitor     = 0x21580001
	FlagReceiveResponse = 0x21580002
	FlagTelemetryData   = 0x21580033
	FlagControlData     = 0x21580041

	// Telemetry frequency band status codes
	TelemetryStatusX  = 0x01 // X频段
	TelemetryStatusUV = 0x02 // UV频段
	TelemetryStatusS  = 0x03 // S频段
)

// Header represents the common header format for all packets
type Header struct {
	TargetCode     []byte // 目标代号 (3 bytes)
	SourceID       uint32 // 信源标识 (4 bytes)
	DestinationID  uint32 // 信宿标识 (4 bytes)
	DataFlag       uint32 // 数据标志 (4 bytes)
	SequenceNumber uint32 // 包序号 (4 bytes)
	Reserved       byte   // 保留字节 (1 byte)
	SendDate       uint16 // 发送日期 (2 bytes)
	SendTime       uint32 // 发送时标 (4 bytes)
	DataLength     uint16 // 数据域长度 (2 bytes)
}

// calculateDateTime calculates the send date and time in the required format
func (h *Header) calculateDateTime() {
	now := time.Now()
	baseDate := time.Date(2000, 1, 1, 0, 0, 0, 0, time.Local)

	// Calculate days since 2000-01-01
	days := uint16(now.Sub(baseDate).Hours()/24) + 1

	// Calculate milliseconds since midnight
	midnight := time.Date(now.Year(), now.Month(), now.Day(), 0, 0, 0, 0, time.Local)
	milliseconds := uint32(now.Sub(midnight).Milliseconds())
	tenthsOfMilliseconds := milliseconds * 10 // Convert to 0.1ms units

	h.SendDate = days
	h.SendTime = tenthsOfMilliseconds
}

// Bytes converts the header to a byte slice
func (h *Header) Bytes() []byte {
	buf := make([]byte, HeaderLength)

	// Write target code (3 bytes)
	copy(buf[0:3], h.TargetCode[:])

	// Write other fields
	binary.LittleEndian.PutUint32(buf[3:7], h.SourceID)
	binary.LittleEndian.PutUint32(buf[7:11], h.DestinationID)
	binary.LittleEndian.PutUint32(buf[11:15], h.DataFlag)
	binary.LittleEndian.PutUint32(buf[15:19], h.SequenceNumber)
	buf[19] = h.Reserved
	binary.LittleEndian.PutUint16(buf[20:22], h.SendDate)
	binary.LittleEndian.PutUint32(buf[22:26], h.SendTime)
	binary.LittleEndian.PutUint16(buf[26:28], h.DataLength)

	return buf
}

// Parse parses a byte slice into a header
func Parse(data []byte) (*Header, error) {
	if len(data) < HeaderLength {
		return nil, ErrInvalidHeaderLength
	}

	h := &Header{}

	// Read target code
	h.TargetCode = data[0:3]

	// Read other fields
	h.SourceID = binary.LittleEndian.Uint32(data[3:7])
	h.DestinationID = binary.LittleEndian.Uint32(data[7:11])
	h.DataFlag = binary.LittleEndian.Uint32(data[11:15])
	h.SequenceNumber = binary.LittleEndian.Uint32(data[15:19])
	h.Reserved = data[19]
	h.SendDate = binary.LittleEndian.Uint16(data[20:22])
	h.SendTime = binary.LittleEndian.Uint32(data[22:26])
	h.DataLength = binary.LittleEndian.Uint16(data[26:28])

	return h, nil
}

type DataPacket struct {
	Header *Header
	Data   []byte // 当前时刻，相对于北京时当日的积秒，量化单位为0.1ms
}

func (p *DataPacket) Bytes() []byte {
	headerBytes := p.Header.Bytes()
	return append(headerBytes, p.Data...)
}

func NewDataPacket(sourceID uint32, destID uint32, targetCode []byte, data []byte) *DataPacket {
	// Create target code bytes for link monitor (0xFFFFF0)
	//targetCode := [3]byte{0xF0, 0xFF, 0xFF} // Stored in little-endian format

	// Calculate current time in 0.1ms units since midnight

	// Create header
	header := &Header{
		TargetCode:     targetCode,
		SourceID:       sourceID,
		DestinationID:  destID,
		DataFlag:       FlagControlData,
		SequenceNumber: 0, // Should be managed by the sender
		Reserved:       0,
		DataLength:     cast.ToUint16(len(data)), // Fixed at 4 bytes for link monitor
	}

	// Calculate send date and time
	header.calculateDateTime()

	return &DataPacket{
		Header: header,
		Data:   data,
	}
}
